# -*- encoding: utf-8 -*-
"""
@File    : down_file.py
@Time    : 2021/8/26 18:23
@Author  : zhouys4
"""
import os
import paramiko as paramiko
from paramiko.message import Message
from paramiko.sftp import CMD_STATUS
from paramiko.common import DEBUG
from paramiko.py3compat import long
from paramiko.sftp_attr import SFTPAttributes
from paramiko.ssh_exception import SSHException
import logging
from datetime import datetime
from dateutil.parser import *
import pymongo

local_path = '/tmp/ftp_file_2017/'
remote_path = '/'
"""
dir_path--ftp路径
new_path--解压后的路径，服务器路径
file_name--文件名
other_url--文件在ftp的绝对路径

"""
logging.basicConfig(level=logging.INFO)

from utils.pack_mysql import MySqLHelper

db = MySqLHelper()



def query_other_url():
    sql1 = 'select * from get_other_url where submit_date>="2017-01-01" and submit_date < "2018-01-01"'
    ret = db.selectall(sql=sql1)
    return ret
    # ret_list = list(ret)
    # print(ret_list[1].decode())



# 下载完成
def down_success(table, other_url):
    sql2 = 'insert into {table} (other_url) VALUES (%s)'.format(table=table)
    ret = db.insertone(sql2, (other_url))
    return ret


# 下载失败
def down_error(table, other_url):
    sql2 = 'insert into {table} (other_url) VALUES (%s)'.format(table=table)
    ret = db.insertone(sql2, (other_url))
    return ret


# 设置服务器的编码，如果服务器是windows的用gbk，是linux用utf-8
def u(s, encoding="gbk"):
    """cast bytes or unicode to unicode"""
    if isinstance(s, bytes):
        return s.decode(encoding)
    elif isinstance(s, str):
        return s
    else:
        raise TypeError("Expected unicode or bytes, got {!r}".format(s))


b_slash = b"/"


class NEWMessage(Message):
    def get_text(self):
        """
        Fetch a Unicode string from the stream.
        """
        return u(self.get_string())


# 设置服务器的编码，如果服务器是windows的用gbk，是linux用utf-8
def b(s, encoding="gbk"):
    """cast unicode or bytes to bytes"""
    if isinstance(s, bytes):
        return s
    elif isinstance(s, str):
        return s.encode(encoding)
    else:
        raise TypeError("Expected unicode or bytes, got {!r}".format(s))


class NewSFTPClient(paramiko.SFTPClient):

    def _adjust_cwd(self, path):
        """
        Return an adjusted path if we're emulating a "current working
        directory" for the server.
        """
        path = b(path)
        if self._cwd is None:
            return path
        if len(path) and path[0:1] == b_slash:
            # absolute path
            return path
        if self._cwd == b_slash:
            return self._cwd + path
        return self._cwd + b_slash + path

    def _async_request(self, fileobj, t, *arg):
        self._lock.acquire()
        try:
            msg = NEWMessage()
            msg.add_int(self.request_number)
            for item in arg:
                if isinstance(item, long):
                    msg.add_int64(item)
                elif isinstance(item, int):
                    msg.add_int(item)
                elif isinstance(item, SFTPAttributes):
                    item._pack(msg)
                else:
                    msg.add_string(item)
            num = self.request_number
            self._expecting[num] = fileobj
            self.request_number += 1
        finally:
            self._lock.release()
        self._send_packet(t, msg)
        return num

    def _read_response(self, waitfor=None):
        while True:
            try:
                t, data = self._read_packet()
            except EOFError as e:
                raise SSHException("Server connection dropped: {}".format(e))
            msg = NEWMessage(data)
            num = msg.get_int()
            self._lock.acquire()
            try:
                if num not in self._expecting:
                    self._log(DEBUG, "Unexpected response #{}".format(num))
                    if waitfor is None:
                        break
                    continue
                fileobj = self._expecting[num]
                del self._expecting[num]
            finally:
                self._lock.release()
            if num == waitfor:
                if t == CMD_STATUS:
                    self._convert_status(msg)
                return t, msg
            if fileobj is not type(None):  # noqa
                fileobj._async_response(t, msg, num)
            if waitfor is None:
                break
        return None, None


class DownFile(object):
    def query_other_url(self):
        # 将修改时间格式 MongoDB中使用
        res_list = query_other_url()
        for other_url_tuple in res_list:
            other_url_list = list(other_url_tuple)
            host = '10.99.60.211'  # 主机
            port = 22  # 端口
            username = 'icacadmin'  # 用户名
            password = 'ICACicac@01'  # 密码
            client = paramiko.Transport(host, port)  # 连接服务器
            client.banner_timeout = 39
            client.connect(username=username, password=password)
            sftp = NewSFTPClient.from_transport(client)
            file = other_url_list[1].decode()
            if not os.path.isdir(local_path):
                os.makedirs(local_path)
            local = local_path + file  # 输入本地文件路径
            remote = remote_path + file  # 远程文件或目录
            logging.info(("下载的文件={} ".format(str(file)), " 时间={}".format(str(datetime.now()))))
            self.download_file_tree(sftp, local, remote, file)
            client.close()

    # 下载文件
    def download_file_tree(self, sftp, LocalFile, RemoteFile, file_name):  # 下载单个文件
        try:
            file_handler = open(LocalFile, 'wb')  # wb 以二进制格式打开文件写入
            sftp.get(RemoteFile, LocalFile)  # 下载目录中文件
            file_handler.close()
            down_success('down_success', other_url=file_name)
            return True
        except Exception as e:
            down_error('down_error', other_url=file_name)
            logging.error(e)

if __name__ == '__main__':
    # query_other_url()
    down = DownFile()
    down.query_other_url()